#include "DASystemInfo.h"
#include "SysInfo/SysInfo.h"
#include <QFile>
#include <QStringList>
#include <QTextStream>
#include <QtMath>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPainter>
#include <QRect>
#include <QDebug>
#include <QPen>
#include <QRegularExpression>
#if defined(Q_OS_WIN)
    #include <winsock.h>
    #include <iphlpapi.h>
    #include <iostream>
#endif

DASystemInfo::DASystemInfo(QWidget *parent)
    : QWidget{parent}
{
    SysInfo::instance().init();
    LabelMem.setParent(this);
    LabelMem.setObjectName("LabelMem");
    LabelMem.setText("MEM:");
    LabelMem.setFixedWidth(50);

    LabelCPU.setParent(this);
    LabelCPU.setObjectName("LabelCPU");
    LabelCPU.setText("CPU:");
    LabelCPU.setFixedWidth(50);

    MemRate.setParent(this);
    MemRate.setObjectName("MemRate");
    MemRate.setFixedWidth(50);

    CPURate.setParent(this);
    CPURate.setObjectName("CPURate");
    CPURate.setFixedWidth(50);

    LabelUpload.setParent(this);
    LabelUpload.setObjectName("LabelUpload");
    LabelUpload.setText("↑:");
    LabelUpload.setFixedWidth(30);

    LabelDownload.setParent(this);
    LabelDownload.setObjectName("LabelDownload");
    LabelDownload.setText("↓:");
    LabelDownload.setFixedWidth(30);

    UploadRate.setParent(this);
    UploadRate.setObjectName("UploadRate");
    UploadRate.setFixedWidth(80);

    DownloadRate.setParent(this);
    DownloadRate.setObjectName("DownloadRate");
    DownloadRate.setFixedWidth(80);

    timer = new QTimer(this);
    connect(timer,&QTimer::timeout,[=](){
        CPURate.setText(getCpuUsed());
        MemRate.setText(getMemUsed());
        getNetUploadDownload();
    });
    timer->start(1000);

    QHBoxLayout *hbl1 =new QHBoxLayout();
    hbl1->addWidget(&LabelMem);
    hbl1->addWidget(&MemRate);
    hbl1->addWidget(&LabelUpload);
    hbl1->addWidget(&UploadRate);

    QHBoxLayout *hbl2 =new QHBoxLayout();
    hbl2->addWidget(&LabelCPU);
    hbl2->addWidget(&CPURate);
    hbl2->addWidget(&LabelDownload);
    hbl2->addWidget(&DownloadRate);

    QVBoxLayout *vbl =new QVBoxLayout();
    vbl->addLayout(hbl1);
    vbl->addLayout(hbl2);
    setLayout(vbl);


}

void DASystemInfo::paintEvent(QPaintEvent *e)
{
    //创建绘画对象
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing); // 反锯齿;
    painter.setBrush(QBrush(QColor(255, 255, 255, 100)));
    painter.setPen(Qt::transparent);

    QRect rect = this->rect();
    rect.setWidth(rect.width()-1);
    rect.setHeight(rect.height()-1);
    painter.drawRoundedRect(rect,5,5);

//    QPen pen;
//    pen.setColor(Qt::red);
//    pen.setWidth(0);
//    painter.setPen(pen);
//    painter.drawRect(this->rect());
//    painter.end();
    QWidget::paintEvent(e);
}

QString DASystemInfo::getCpuUsed()
{
    double res = SysInfo::instance().cpuLoadAverage();
    if ( res < 50.0)
    {
        CPURate.setStyleSheet("QLabel{ color:rgb(124,252,0)}");
    }
    if (res > 50.0)
    {
        CPURate.setStyleSheet("QLabel{ color:rgb(255,215,0)}");
    }
    if (res > 80.0)
    {
        CPURate.setStyleSheet("QLabel{ color:rgb(255,0,0)}");
    }

    QString result= QString("%1%").arg(res, 0, 'f', 2, QLatin1Char(' '));
    return result;
}

QString DASystemInfo::getMemUsed()
{
    double res = SysInfo::instance().memoryUsed();
    if (res < 50)
    {
        MemRate.setStyleSheet("QLabel{ color:rgb(124,252,0)}");
    }
    if (res > 50)
    {
        MemRate.setStyleSheet("QLabel{ color:rgb(255,215,0)}");
    }
    if (res > 80)
    {
        MemRate.setStyleSheet("QLabel{ color:rgb(255,0,0)}");
    }
    QString result = QString("%1%").arg(res, 0, 'f', 2, QLatin1Char(' '));
    return result;
}

QString DASystemInfo::setRateUnitSensitive(DASystemInfo::RateUnit unit, DASystemInfo::Sensitive sensitive)
{
    switch (sensitive)
    {
        case Sensitive::Default:
        {
            switch (unit)
            {
                case RateUnit::RateBit:
                    return QString("b/s");
                case RateUnit::RateByte:
                    return QString("B/s");
                case RateUnit::RateKb:
                    return QString("Kb/s");
                case RateUnit::RateMb:
                    return QString("Mb/s");
                case RateUnit::RateGb:
                    return QString("Gb/s");
                case RateUnit::RateTb:
                    return QString("Tb/s");
                default:
                    //            qDebug()<<QString("Sensitive::Default,  RateUnit is RateUnknow.");
                    return QString("");
            }
        }
        case Sensitive::Upper:
        {
            switch (unit)
            {
                case RateUnit::RateBit:
                    return QString("BIT/S");
                case RateUnit::RateByte:
                    return QString("B/S");
                case RateUnit::RateKb:
                    return QString("KB/S");
                case RateUnit::RateMb:
                    return QString("MB/S");
                case RateUnit::RateGb:
                    return QString("GB/S");
                case RateUnit::RateTb:
                    return QString("TB/S");
                default:
                    //            qDebug()<<QString("Sensitive::Upper,  RateUnit is RateUnknow.");
                    return QString("");
            }
        }
        case Sensitive::Lower:
        {
            switch (unit)
            {
                case RateUnit::RateBit:
                    return QString("bit/s");
                case RateUnit::RateByte:
                    return QString("b/s");
                case RateUnit::RateKb:
                    return QString("kb/s");
                case RateUnit::RateMb:
                    return QString("mb/s");
                case RateUnit::RateGb:
                    return QString("gb/s");
                case RateUnit::RateTb:
                    return QString("tb/s");
                default:
                    //            qDebug()<<QString("Sensitive::Lower,  RateUnit is RateUnknow.");
                    return QString("");
            }
        }
        default:
        {
            //        qDebug()<<QString("Sensitive is RateUnknow.");
            return QString("");
        }
    }
}

double DASystemInfo::autoRateUnits(long speed, DASystemInfo::RateUnit &unit)
{
    /* 自动判断合适的速率单位,默认传进来的是 Byte
     * bit    0 ~ 7 位 (不到 1 字节)
     * Byte   1    ~ 2^10  Byte
     * KB     2^10 ~ 2^20  Byte
     * MB     2^20 ~ 2^30  Byte
     * GB     2^30 ~ 2^40  Byte
     * TB     2^40 ~ 2^50  Byte
     */

    if (unit != DASystemInfo::RateByte)
    {
        //        qDebug()<<"请先将单位转为字节(byte)后再传参";
        return -1;
    }

    double sp = 0;
    if (0 <= speed && speed < qPow(2, 10))
    {
        unit = DASystemInfo::RateByte;
        sp = speed;
    }
    else if (qPow(2, 10) <= speed && speed < qPow(2, 20))
    {
        unit = DASystemInfo::RateKb;
        sp = static_cast<double>(speed / qPow(2, 10) * 1.0);
    }
    else if (qPow(2, 20) <= speed && speed < qPow(2, 30))
    {
        unit = DASystemInfo::RateMb;
        sp = static_cast<double>(speed / qPow(2, 20) * 1.0);
    }
    else if (qPow(2, 30) <= speed && speed < qPow(2, 40))
    {
        unit = DASystemInfo::RateGb;
        sp = static_cast<double>(speed / qPow(2, 30) * 1.0);
    }
    else if (qPow(2, 40) <= speed && speed < qPow(2, 50))
    {
        unit = DASystemInfo::RateTb;
        sp = static_cast<double>(speed / qPow(2, 40) * 1.0);
    }
    else {
        unit = DASystemInfo::RateUnknow;
        //        qDebug()<<"本设备网络速率单位传输超过 TB, 或者低于 0 Byte.";
        sp = -1;
    }

    return sp;
}

void DASystemInfo::getNetUploadDownload()
{
#if defined(Q_OS_WIN)
//        CspeedDuplexDlg *pDlg= (CspeedDuplexDlg *)lpParameter;
        PMIB_IFTABLE	m_pTable = NULL;
        DWORD	 m_dwAdapters = 0;
        ULONG	 uRetCode = GetIfTable(m_pTable, &m_dwAdapters, TRUE);
        if (uRetCode == ERROR_NOT_SUPPORTED)
        {
            //return (-1);
            exit(-1);
        }

        if (uRetCode == ERROR_INSUFFICIENT_BUFFER)
        {
            m_pTable = (PMIB_IFTABLE)new BYTE[65535];										//假设端口数不超过65535个
        }

        DWORD	dwLastIn = 0;																			//上一秒钟的接收字节数
        DWORD	dwLastOut = 0;																			//上一秒钟的发送字节数
        DWORD	dwBandIn = 0;																			//下载速度
        DWORD	dwBandOut = 0;																			//上传速度

        while (1)
        {
            GetIfTable(m_pTable, &m_dwAdapters, TRUE);
            DWORD	dwInOctets = 0;
            DWORD	dwOutOctets = 0;

            //将所有端口的流量进行统计
            for (UINT i = 0; i < m_pTable->dwNumEntries; i++)
            {
                MIB_IFROW	Row = m_pTable->table[i];
                dwInOctets += Row.dwInOctets;
                dwOutOctets += Row.dwOutOctets;
            }

            dwBandIn = dwInOctets - dwLastIn;	//下载速度
            dwBandOut = dwOutOctets - dwLastOut;	//上床速速
            if (dwLastIn <= 0)
            {
                dwBandIn = 0;
            }
            else
            {
                dwBandIn = dwBandIn / 1024;	//b转换成kb
            }

            if (dwLastOut <= 0)
            {
                dwBandOut = 0;
            }
            else
            {
                dwBandOut = dwBandOut / 1024;	//b转换成kb
            }

            dwLastIn = dwInOctets;
            dwLastOut = dwOutOctets;
        }

        printf("收到字节: %u bytes\n", dwLastIn);
        printf("发送字节: %u bytes\n", dwLastOut);
        printf("下行速度: %u KB\n", dwBandIn);
        printf("上行速度: %u KB\n", dwBandOut);
        printf("--------------------------\n");
        delete[] m_pTable;
        return ;
#elif defined(Q_OS_LINUX)
    long uploadAll = 0;
    long downloadAll = 0;

    long upload = 0;
    long download = 0;

    QFile file("/proc/net/dev");
    file.open(QIODevice::ReadOnly | QIODevice::Text);
    QTextStream stream(&file);
    QString line = stream.readLine();
    line  = stream.readLine();
    line  = stream.readLine();
    while (!line.isNull()) {
        line = line.trimmed();
        QStringList list = line.split(QRegularExpression("\\s{1,}"));   // 匹配任意 大于等于1个的 空白字符

        if (!list.isEmpty()) {
            upload = list.at(9).toLong();
            download = list.at(1).toLong();
        }

        uploadAll += upload;
        downloadAll += download;
        line  = stream.readLine();
    }
    RateUnit upunit = RateByte;
    RateUnit dounit = RateByte;
    Sensitive  sensitive = Upper;
    double upspeed = autoRateUnits((uploadAll - old_upload) / (timer->interval() / 1000), upunit);
    double dospeed = autoRateUnits((downloadAll - old_download) / (timer->interval() / 1000), dounit);

    UploadRate.setText(QString("%1").arg(upspeed, 0, 'f', 2, QLatin1Char(' ')) + setRateUnitSensitive(upunit,sensitive));
    DownloadRate.setText(QString("%1").arg(dospeed, 0, 'f', 2, QLatin1Char(' ')) + setRateUnitSensitive(dounit,sensitive));

    old_upload = uploadAll;
    old_download = downloadAll;
#endif
}
